package ji

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type HandlerFunc func(ctx *Context)

type Context struct {
	response http.ResponseWriter
	request  *http.Request

	method string
	path   string
	Params map[string]string

	statusCode int

	middlewares []HandlerFunc
	index       int

	templates
}

func newContext(w http.ResponseWriter, r *http.Request) *Context {
	return &Context{
		response: w,
		request:  r,
		method:   r.Method,
		path:     r.URL.Path,

		index: -1,
	}
}

func (c *Context) status(code int) {
	c.statusCode = code
	c.response.WriteHeader(c.statusCode)

}

func (c *Context) setHeader(key, value string) {
	c.response.Header().Set(key, value)
}

func (c *Context) GetMethod() string {
	return c.method
}
func (c *Context) GetPath() string {
	return c.path
}
func (c *Context) GetStatusCode() int {
	return c.statusCode
}

func (c *Context) Param(key string) string {
	return c.Params[key]
}

func (c *Context) PostForm(key string) string {
	return c.request.FormValue(key)
}

func (c *Context) Query(key string) string {
	return c.request.URL.Query().Get(key)
}

func (c *Context) JSON(code int, obj interface{}) {
	c.setHeader("Content-Type", "application/json")
	c.status(code)
	encoder := json.NewEncoder(c.response)
	if err := encoder.Encode(obj); err != nil {
		http.Error(c.response, err.Error(), 500)
	}
}

func (c *Context) HTML(code int, html string) {
	c.setHeader("Content-Type", "text/html")
	c.status(code)
	c.response.Write([]byte(html))
}

func (c *Context) HTML2(code int, fileName string, data interface{}) {
	c.setHeader("Content-Type", "text/html")
	c.status(code)
	if err := c.templates.htmlTemplates.ExecuteTemplate(c.response, fileName, data); err != nil {
		c.Fail(500, err.Error())
	}
}

func (c *Context) String(code int, format string, values ...interface{}) {
	c.setHeader("Content-Type", "text/plain")
	c.status(code)
	c.response.Write([]byte(fmt.Sprintf(format, values...)))
}

func (c *Context) Data(code int, data []byte) {
	c.status(code)
	c.response.Write(data)
}

// Next 移交中间件的执行权 并执行下一个中间件 | 执行所有的处理函数
func (c *Context) Next() {
	c.index++
	for ; c.index < len(c.middlewares); c.index++ {
		c.middlewares[c.index](c)
	}
}

// Fail 停止调用后续中间件
func (c *Context) Fail(code int, err string) {
	c.index = len(c.middlewares)
	c.JSON(code, H{"message": err})
}

// Abort  停止调用后续中间件
func (c *Context) Abort() {
	c.index = len(c.middlewares)
}
